package com.wqh.article.controller;

import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.command.AsyncResult;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.wqh.article.command.*;
import com.wqh.article.entity.User;
import com.wqh.article.service.ArticleService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author wanqh
 * @date 2018/01/11 9:29
 * @description:
 */
@RestController
public class ArticleController {

    private final Logger logger = LoggerFactory.getLogger(ArticleController.class);

    @Autowired
    private ArticleService articleService;

    @Autowired
    private EurekaClient eurekaClient;

    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * 使用EurekaClient
     * @return
     */
    @GetMapping("/eureka_instance")
    public String serviceUrl(){
        InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("article-service", false);
        return instanceInfo.getHomePageUrl();
    }

    /**
     * 获取当前实例信息
     * @return
     */
    @GetMapping("/service-info")
    public List<ServiceInstance> shwoInfo(){
        ServiceInstance localServiceInstance = this.discoveryClient.getLocalServiceInstance();
        List<ServiceInstance> instances = this.discoveryClient.getInstances("article-service");
        return instances;
    }


    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/a/u/{id}")
    public User getUser(@PathVariable("id") Long id){
        return restTemplate.getForObject("http://USER-SERVICE/user/{1}",User.class,id);
    }

    /**
     * 使用Hystrix断路器
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "fallback")
    @GetMapping("/hystrix/{id}")
    public User findUserHystrix(@PathVariable("id") Long id){
//        int i = 1/0;
        return restTemplate.getForObject("http://USER-SERVICE/user/{1}",User.class,id);
    }

    /**
     * 服务降级方法
     * @param id
     * @param throwable
     * @return
     */
    private User fallback(Long id,Throwable throwable){
        LoggerFactory.getLogger(ArticleController.class).info("========{}=============",throwable.getMessage());
        return new User();
    }

    /**
     * 使用继承方式
     * @param id
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @GetMapping("/command/{id}")
    public User findUserCommand(@PathVariable("id") Long id) throws ExecutionException, InterruptedException {
//        HystrixRequestContext.initializeContext();
//        com.netflix.hystrix.HystrixCommand.Setter setter1 = com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("userCommand"));
        UserCommand u1 = new UserCommand(restTemplate,id);
        UserCommand u2 = new UserCommand(restTemplate,id);
        UserCommand u3 = new UserCommand(restTemplate,id);
        UserCommand u4 = new UserCommand(restTemplate,id);
//        //同步调用
////        User user = userCommand.execute();
//        //异步请求
////        Future<User> queue = userCommand.queue();
////        User user = queue.get();
//
        User user1 = u1.execute();
        System.out.println("第一次请求"+user1);
        User user2 = u2.execute();
        System.out.println("第二次请求"+user2);
        User user3 = u3.execute();
        System.out.println("第三次请求"+user3);
        User user4 = u4.execute();
        System.out.println("第四次请求"+user4);
        return user1;
    }

    @HystrixCommand
    @GetMapping("/async/{id}")
    public Future<User> findUserAsync(@PathVariable("id") Long id){
        return new AsyncResult<User>() {
            @Override
            public User invoke() {
                return restTemplate.getForObject("http://USER-SERVICE/user/{1}",User.class,id);
            }
        };
    }

    /**
     * 测试注解缓存
     * @param id
     * @return
     */
    @GetMapping("/cache/{id}")
    public User findUserCache(@PathVariable("id") Long id){
        HystrixRequestContext.initializeContext();
        User user1  = articleService.getUserById(id);
        System.out.println("第一次请求"+user1);
        User user2 = articleService.getUserById(id);
        System.out.println("第二次请求"+user2);
        User user3 = articleService.getUserById(id);
        System.out.println("第三次请求"+user3);
        User user4 =articleService.getUserById(id);
        System.out.println("第四次请求"+user4);
       return articleService.getUserById(id);
    }

    @GetMapping("/getcommand/{id}")
    public User testGetCommand(@PathVariable("id") Long id){
        GetUserCommand u1 = new GetUserCommand(restTemplate,id);
        GetUserCommand u2 = new GetUserCommand(restTemplate,id);
        GetUserCommand u3 = new GetUserCommand(restTemplate,id);
        GetUserCommand u4 = new GetUserCommand(restTemplate,id);
        User user1 = u1.execute();
        System.out.println("第一次请求"+user1);
        User user2 = u2.execute();
        System.out.println("第二次请求"+user2);
        User user3 = u3.execute();
        System.out.println("第三次请求"+user3);
        User user4 = u4.execute();
        System.out.println("第四次请求"+user4);
        return user1;
    }

    @PostMapping("/postcommand")
    public User testPostCommand(User user){
        HystrixRequestContext.initializeContext();
        PostUserCommand u1 = new PostUserCommand(restTemplate,user);
        User execute = u1.execute();
        return execute;
    }

    @PostMapping("/cacheremove")
    public User testCacheRemove(User user){
        return articleService.update(user);
    }

    @GetMapping("/testBathCommand")
    public List<User> testBathCommand() throws ExecutionException, InterruptedException {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        UserCollapdeCommand u1 = new UserCollapdeCommand(articleService, 1L);
        UserCollapdeCommand u2 = new UserCollapdeCommand(articleService, 2L);
        UserCollapdeCommand u3 = new UserCollapdeCommand(articleService, 3L);
        UserCollapdeCommand u4 = new UserCollapdeCommand(articleService, 4L);
        Future<User> q1 = u1.queue();
        Future<User> q2 = u2.queue();
        Future<User> q3 = u3.queue();
        Future<User> q4 = u4.queue();
        User e1 = q1.get();
        User e2 = q2.get();
        User e3 = q3.get();
        User e4 = q4.get();
        List<User> res = new ArrayList<>();
        res.add(e1);
        res.add(e2);
        res.add(e3);
        res.add(e4);
        System.out.println(res);
        return res;
    }

    @GetMapping("/testBathCommandAnn")
    public List<User> testBathCommandAnn() throws ExecutionException, InterruptedException {
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        Future<User> q1 = articleService.findOne(1L);
        Future<User> q2 = articleService.findOne(2L);
        Future<User> q3 = articleService.findOne(3L);
        Future<User> q4 = articleService.findOne(4L);
        User e1 = q1.get();
        User e2 = q2.get();
        User e3 = q3.get();
        User e4 = q4.get();
        List<User> res = new ArrayList<>();
        res.add(e1);
        res.add(e2);
        res.add(e3);
        res.add(e4);
        System.out.println(res);
        return res;
    }

}
